#include "spiffs.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "driver/gpio.h"

static const char *TAG = "spiffs";

uint8_t countNonZero(uint16_t* arr, uint8_t size) 
{
    int count = 0;
    for (int i = 0; i < size; i++) 
    {
        if (arr[i] != 0) 
        {
            count++;
        }
    }
    return count;
}

void spiffs_init(esp_vfs_spiffs_conf_t conf)
{
    //初始化和挂载spiffs分区
    esp_err_t ret = esp_vfs_spiffs_register(&conf);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount or format filesystem");
        } else if (ret == ESP_ERR_NOT_FOUND) {
            ESP_LOGE(TAG, "Failed to find SPIFFS partition");
        } else {
            ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
        }
        return;
    }

    //执行SPIFFS文件系统检查
    ESP_LOGI(TAG, "Performing SPIFFS_check().");
    ret = esp_spiffs_check(conf.partition_label);//操作spiffs文件系统器件断电，可能会导致 SPIFFS 损坏，可通过esp_spiffs_check恢复
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret));
        return;
    } else {
        ESP_LOGI(TAG, "SPIFFS_check() successful");
    }

    //获取SPIFFS可用区域大小
    size_t total = 0, used = 0;
    ret = esp_spiffs_info(conf.partition_label, &total, &used);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));
        esp_spiffs_format(conf.partition_label);
        return;
    } else {
        ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
    }

    //可用空间异常，执行SPIFFS检查
    if (used > total) {
        ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check().");
        ret = esp_spiffs_check(conf.partition_label);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret));
            return;
        } else {
            ESP_LOGI(TAG, "SPIFFS_check() successful");
        }
    }
    
}


void spiffs_destroy(esp_vfs_spiffs_conf_t conf)
{
    esp_vfs_spiffs_unregister(conf.partition_label);
    ESP_LOGI(TAG, "SPIFFS unmounted");
}

void Information_Write_One(Infomation_t* prevous,esp_vfs_spiffs_conf_t conf)
{
    //spiffs_init(conf);
    
    Infomation_t* current = prevous;
    FILE* pf = fopen("/spiffs/information.dat","a+");
    if (pf == NULL) 
    {
         ESP_LOGE(TAG, "Failed to open file for read");
         gpio_set_level(LED_GPIO,!gpio_get_level(LED_GPIO));
         return;
    }
    fwrite(current,sizeof(Infomation_t),1,pf);
    fclose(pf);
    pf = NULL;

    //spiffs_destroy(conf);
}

void Information_Write_All(Infomation_t* prevous,esp_vfs_spiffs_conf_t conf,uint16_t* ID)
{
    uint8_t num = countNonZero(ID,32);
    uint8_t i = 0;
    //spiffs_init(conf);
    FILE* pf = fopen("/spiffs/information.dat","w");
    if (pf == NULL) 
    {
         ESP_LOGE(TAG, "Failed to open file for read");
         gpio_set_level(LED_GPIO,!gpio_get_level(LED_GPIO));
         return;
    }
    Infomation_t* current = prevous;
    while(current->next != NULL)
    {
        current = current->next;
        fwrite(current,sizeof(Infomation_t),1,pf);  
    }
    for(i = 1;i < num;i++)
    {
        fwrite(&(ID[i]),sizeof(uint16_t),1,pf);
    }
    fclose(pf);
    pf = NULL;
    //spiffs_destroy(conf);
}

uint8_t Information_Read(Infomation_t* previous,esp_vfs_spiffs_conf_t conf,uint16_t* ID)
{
    uint8_t i = 0;
    spiffs_init(conf);
    FILE* pf = fopen("/spiffs/information.dat","r");
    if (pf == NULL) 
    {
         ESP_LOGE(TAG, "Failed to open file for read");
         gpio_set_level(LED_GPIO,!gpio_get_level(LED_GPIO));
         return 0;
    }
    Infomation_t* Ptail = previous;
    while(Ptail->next != NULL)
    {
        Ptail = Ptail->next;
    }
    fseek(pf,0,SEEK_END);
    long bit = ftell(pf);
    uint8_t num = bit / 832;
    uint8_t num_de = (bit % 832) / sizeof(uint16_t);
    fseek(pf,0,SEEK_SET);
    for(i = 0;i < num;i++)
    {
        Infomation_t* current = (Infomation_t*)malloc(sizeof(Infomation_t));
        Ptail->next = current;
        Ptail = Ptail->next;
        fread(current,sizeof(Infomation_t),1,pf);
        Ptail->next = NULL;
    }
    for(i = 1;i < num_de + 1;i++)
    {
        fread(&(ID[i]),sizeof(uint16_t),1,pf);
    }

    fclose(pf);
    pf = NULL;

    //spiffs_destroy(conf);
    ESP_LOGI(TAG, "--------%ld-------",bit);
    return num + num_de;
    
}